﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace wspol_zad4
{
    public class Buffors
    {
        private bool exit = false;

        //Bufory cykliczne
        private int[] b1;
        private int[] b2;

        //nastepna wolna pozycja
        private int b1PositionProducer;
        //nastepny element do konsumpcji
        private int b1PositionConsumer;

        private int b2Position;

        //Ile elementow znajduje sie aktualnie w tablicy
        private int b1Count;
        private int b2Count;

        //Obiekty synchronizacji
        /*private readonly object producer;
        private readonly object consumer;
        private readonly object cleared;
        private readonly object clear;*/

        private ManualResetEvent b1PutBegin;
        private AutoResetEvent b1PutEnd;
        private object b1PutLock;
        private int b1PutElem;

        private ManualResetEvent b1GetBegin;
        private AutoResetEvent b1GetEnd;
        private object b1GetLock;
        private int b1GetElem;

        private ManualResetEvent b2PutBegin;
        private AutoResetEvent b2PutEnd;
        private object b2PutLock;
        private int b2PutElem;

        private ManualResetEvent b2ClearBegin;
        private AutoResetEvent b2ClearEnd;
        private object b2ClearLock;
        

        public Buffors(int b1Cnt, int b2Cnt)
        {
            b1 = new int[b1Cnt];
            b2 = new int[b2Cnt];

            /*producer = new object();
            consumer = new object();
            clear = new object();
            cleared = new object();*/

            b1Count = 0;
            b2Count = 0;
            b1PositionProducer = 0;
            b1PositionConsumer = 0;
            b2Position = 0;

            b1PutBegin = new ManualResetEvent(false);
            b1PutEnd = new AutoResetEvent(false);
            b1PutLock = new object();

            b1GetBegin = new ManualResetEvent(false);
            b1GetEnd = new AutoResetEvent(false);
            b1GetLock = new object();

            b2PutBegin = new ManualResetEvent(false);
            b2PutEnd = new AutoResetEvent(false);
            b2PutLock = new object();

            b2ClearBegin = new ManualResetEvent(false);
            b2ClearEnd = new AutoResetEvent(false);
            b2ClearLock = new object();
        }

        //Wstaw do b1
        /*
         * Wstaw do b1 jezeli nie jest pelny.
         * Jezeli jest pelny to czekaj.
         * wstaw na pozycje b1Position i ustaw odpowiednia nastepna pozycje
         * zwieksz liczbe elementow
         * zasygnalizuj konsumenta
         */
        public void b1Put(int elem)
        {
            lock (b1PutLock)
            {
                b1PutElem = elem;
                b1PutBegin.Set();
                b1PutEnd.WaitOne();
            }
        }

        //Punkt wejscia
        //Pobierz z b1
        public void b1Get(out int value)
        {            
            lock (b1GetLock)
            {
                b1GetBegin.Set();
                b1GetEnd.WaitOne();
                value = b1GetElem;
            }           
        }

        //Punkt wejścia
        //Wstaw do b2
        public void b2Put(int elem)
        {
            lock (b2PutLock)
            {
                b2PutElem = elem;
                b2PutBegin.Set();
                b2PutEnd.WaitOne();        
            }
            
        }

        //Punkt wejścia
        //Oproznij b2
        public void b2Clear()
        {
            lock (b2ClearLock)
            {
                b2ClearBegin.Set();
                b2ClearEnd.WaitOne();
            }
        }

        public string PrepareStringData()
        {
            string s = "";
            //lock (b1PutLock)
                //lock (b1GetLock)
                    //lock(b2PutLock)
                        //lock(b2ClearLock)
                {
                    string s1 = "B1: ";
                    string s2 = "B2: ";

                    for (int i = 0; i < b1.Length; i++)
                        s1 += b1[i].ToString() + ";";

                    for (int i = 0; i < b2.Length; i++)
                        s2 += b2[i].ToString() + ";";

                    s1 += "\n\r";
                    s2 += "\n\r";

                    s = s1 + s2;
                }
            return s;
        }

        //Watek bufora 2. Zapewnia dodawanie elementów do bufora 2 i jego opróżnianie

        public void RunBuffor1()
        {
            while (!exit)
            {
                //Pozwol wejsc put
                if (b1Count < b1.Length && b1PutBegin.WaitOne(20, false))
                {
                    b1[b1PositionProducer] = b1PutElem;
                    b1PositionProducer = (b1PositionProducer + 1) % b1.Length;
                    b1Count++;
                    b1PutBegin.Reset();
                    b1PutEnd.Set();
                }

                //pozwol wejsc get
                if (b1Count > 0 && b1GetBegin.WaitOne(20, false))
                {
                    b1GetElem = b1[b1PositionConsumer];
                    b1[b1PositionConsumer] = -1;
                    b1PositionConsumer = (b1PositionConsumer + 1) % b1.Length;
                    b1Count--;
                    b1GetBegin.Reset();
                    b1GetEnd.Set();
                }
            }
        }

        public void RunBuffor2()
        {
            while (!exit)
            {
                //Wpuszczanie dla wątków dodajacych element
                if (b2Count < b2.Length && b2PutBegin.WaitOne(20, false))
                {
                    b2[b2Position] = b2PutElem;
                    b2Position = (b2Position + 1) % b2.Length;
                    b2Count++;
                    b2PutBegin.Reset();
                    b2PutEnd.Set();
                }

                if (b2Count >= b2.Length && b2ClearBegin.WaitOne(20, false))
                {
                    b2Position = 0;
                    b2Count = 0;

                    for (int i = 0; i < b2.Length; i++)
                        b2[i] = -1;

                    b2ClearBegin.Reset();
                    b2ClearEnd.Set();
                }
            }
        }

        public void Exit()
        {
            exit = true;
        }
    }
}
